from types import NoneType
from typing import Union, Callable, Optional, Any, Sequence, overload

from common.core.globals import p, PageObject
from common.core.meta import ApiAlias, ApiAliasMeta

from common.pkg.log import INFO
import settings


class WebdriverApi(ApiAlias, metaclass=ApiAliasMeta):
    def __init__(self, alias: str):
        super().__init__(alias=alias)
        self.retry = False
        self.setup = None
        self.callback = None
        self.scroll_to = False
        self.raise_error = True

    def __get__(self, page, owner):
        return self

    def __set_name__(self, owner, name):
        self.obj = name

    def __call__(self, *args, **kwargs):
        raise TypeError(f"{self.obj} 不可调用")

    @overload
    def set_conf(
            self,
            retry: Optional[bool] = ...,
            setup: Optional[Union[Callable[[PageObject], Any], Sequence[Callable[[PageObject], Any]]]] = ...,
            callback: Optional[Union[Callable[[PageObject], Any], Sequence[Callable[[PageObject], Any]]]] = ...,
            scroll_to: Optional[bool] = ...,
            raise_error: Optional[bool] = ...,
    ) -> NoneType:
        ...

    def set_conf(
            self,
            retry=False,
            setup=None,
            callback=None,
            scroll_to=False,
            raise_error=True,
    ) -> None:
        self.retry = retry
        self.setup = setup
        self.callback = callback
        self.scroll_to = scroll_to
        self.raise_error = raise_error

    # 执行 set_up
    def _exec_setup(self) -> None:
        if self.setup:
            if isinstance(self.setup, Sequence):
                [s(p) for s in self.setup]
            else:
                self.setup(p)

    # 执行 callback
    def _exec_callback(self) -> None:
        if self.callback:
            if isinstance(self.callback, Sequence):
                [c(p) for c in self.callback]
            else:
                self.callback(p)

    # 执行行为过程
    def _exec_process(self, *args, **kwargs):
        if p.debug or settings.DEBUG:
            input("按回车继续执行>>  ")
        try:
            self._exec_setup()
            rs = self.action(*args, **kwargs)
            self._exec_callback()
        except Exception as e:
            raise e
        return rs

    def action(self, *args, **kwargs) -> Any:
        raise NotImplementedError("未定义用户行为")

    def run(self, *args, **kwargs) -> Any:
        try:
            try:
                return self._exec_process(*args, **kwargs)
            except Exception as e:
                if self.retry:
                    INFO.warning("因为 %s 异常重新执行 %s 操作" % (str(e), self.alias))
                    return self._exec_process(*args, **kwargs)
                else:
                    raise
        except Exception as e:
            if self.raise_error:
                raise e
            else:
                INFO.warning(f"当前 {self.alias} 因 {str(e)} 报错，忽略当前错误并继续执行脚本")
